home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1997 October / macformat-055.iso / mac / Shareware Plus / Developers / VideoToolbox / VideoToolboxSources / Identify.c < prev    next >
Encoding:
Text File  |  1997-04-10  |  32.9 KB  |  973 lines  |  [TEXT/CWIE]

  1. /* NameRegistryLib is in the VideoToolbox:Libs folder. */
  2. //#define NO_NAME_REGISTRY_LIB 1    /* Uncomment this if you're missing Apple's NameRegistryLib */
  3. /*
  4. Identify.c
  5.  
  6. NOTE: several routines that use Apple's NameRegistryLib appear at the end of this file.
  7. If you don't have that file, then un-comment the first line above.
  8.  
  9. Each routine returns an informative C string. Here are samples. (I suggest you
  10. use BreakLines() to printf the longer ones.)
  11.  
  12. IdentifyCompiler:
  13. "Compiled by Metrowerks CodeWarrior C 7.00 for PowerPC, 4B int and 8B double."
  14.  
  15. IdentifyOwner:
  16. "Denis Pelli"
  17.  
  18. IdentifyModel:
  19. "PowerBook 170"
  20.  
  21. IdentifyMachine:
  22. "Denis Pelli's PowerBook 170, 68030, 68882, System 7.1.0."
  23. "Mal's PowerMac 8500/120, ppc604, L2 cache, System 7.5.2."
  24.  
  25. IdentifyVideo(device):
  26. "PowerBook 170 \"Macintosh D Built-In Video\" (.Display_Video_Apple_TIM) in slot 0"
  27. "PowerMac 8500/120 \"Built-in video\" (.Display_Video_Apple_Control)"
  28.  
  29. The computer model appears only if the slot==0, which indicates built-in video. 
  30. Quotes embrace the card name, and parentheses embrace the driver name.
  31. The driver's version number appears only if it's non-zero.
  32.  
  33. HISTORY:
  34. 1/29/92    dgp wrote IdentifyCompiler.
  35. 2/25/92    dgp    wrote IdentifyMachine.
  36. 8/26/92    dgp get owner and model name from the System file
  37. 2/20/93    dgp    added ROM version
  38. 2/27/93    dgp merged IdentifyCompiler.c and IdentifyMachine.c into the new Identify.c,
  39.             and added IdentifyVideo.
  40. 4/25/93    dgp    IdentifyMachine reports 24/32-bit addressing.
  41. 12/14/93 dgp If THINK C compiler version is "5" I report "5 or 6.0" since Symantec
  42.             forgot to increment the version number when they released 6.0. They
  43.             fixed this in version 6.01.
  44. 3/2/94    dgp    Extracted IdentifyOwner from within IdentifyMachine
  45. 7/28/94 dgp added support for Metrowerks CodeWarrior C compiler and PowerPC.
  46.             Eliminated use of "#s" printf format, since it's not supported by
  47.             Metrowerks CodeWarrior C.
  48. 9/5/94 dgp     removed assumption in printf's that int==short.
  49. 9/6/94    dgp    Enhanced IdentifyCompiler to specify the size of int.
  50. 9/6/94    dgp    Disable cache checks on PowerPC, because those traps are undefined.
  51. 10/5/94 dgp Removed all floating point code from IdentifyCompiler().
  52. 11/5/94 dgp Suppressed ROM info in Identify.
  53. 11/9/94 dgp added IdentifyApplication().
  54. 1/15/95 dgp added test for version 5 of CodeWarrior
  55. 5/24/95 dgp added test for version 6 of CodeWarrior
  56. 6/14/95 dgp added GetCPUSpeed() to IdentifyMachine() and abbreviated the report, 
  57.         omitting a lot of boring stuff.
  58. 6/27/95 dgp adjusted UNIVERSAL_HEADERS conditional for GMT struct, to use old
  59.         structure for version 1 universal headers.
  60. 7/20/95    dgp once again, made compatible with pre-universal headers
  61. 8/10/95 dgp updated IdentifyCompiler() for Symantec C.
  62. 9/26/95 dgp updated IdentifyCompiler() for CW7.
  63. 10/5/95 dgp minor editing of IdentifyVideo().
  64. 10/14/95 dgp added support for PCI Macs, using the NameRegistry. Since System 7.5 fails to
  65.         adequately name most Macs, I've reverted to using a built-in table of names in 
  66.         IdentifyModel. IdentifyMachine now also prints the Gestalt machine number to 
  67.         resolve any residual ambiguities.
  68.         IdentifyModel, IdentifyVideo, and IdentifyMachine now give complete information on all
  69.         Macs, provided that when running on PCI Macs they are compiled as PPC code. This 
  70.         limitation is due to the (easy) way that I implemented the calls to Apple's 
  71.         NameRegistryLib. The NameRegistry-related routines appear in a long self-contained
  72.         section at the end of this file.
  73. 10/24/95 dgp added pclk and bclk Gestalt calls, based on gestalt-selectors-31.
  74. 12/4/95 dgp As requested by David Brainard, changed "char *machineName[]" to 
  75.         "char machineName[][32]" so that it would compile as a code resource.
  76. 3/7/96 dgp report system version number in standard  format, e.g. "7.5.3".
  77. 3/18/96 dgp IdentifyModel() now always reports actual clock speed if known.
  78. 5/14/96 dgp Added mach codes for new Macs from GestaltSelectorList 3.3.5.
  79. 5/28/96 dgp Added conditional UNIVERSAL_INTERFACES_VERSION>=0x0212
  80. 2/19/97 dhb Lobotomized this file for case where both MATLAB and THINK_C are
  81.             true. SCREEN.c is over the limit in terms of total code resource
  82.             size that THINK_C can support. This file was huge in terms of its
  83.             data segment, but we weren't actually using much of it. The first
  84.             conditional below puts in just what we need to get the link to work,
  85.             then the old file follows.
  86. 3/8/97    dgp    many minor changes. Added IdentifyProcessor, IdentifyFpu.
  87. 3/19/97    dgp    IdentifyCompiler: divide by 10 in identifying CW compiler.
  88. 4/10/97    dgp    Use latest constants in IdentifyProcessor, as suggested by code snippet
  89.             in April, 1997, Apple Developer CD-ROM.
  90. 4/10/97    dgp    Eliminate stuff that was conditional on !UNIVERSAL_HEADERS.
  91. */
  92. #include "VideoToolbox.h"
  93. char *IdentifyProcessor(void);
  94. char *IdentifyFpu(void);
  95.  
  96. #ifndef __TRAPS__
  97.     #include <Traps.h>        // _HWPriv
  98. #endif
  99. #include <Power.h>
  100. #include <LowMem.h>
  101. void GetCPUProperties(char *cpuName,long *cpuHz,Boolean *hasL2Cache);
  102. void GetVideoProperties(GDHandle device,char *slotName,char *cardName,char *modelName);
  103. char *GetDeviceSlotName(GDHandle device);
  104. #define gestaltBusClockSpeed 'bclk'    /* gestalt-selectors-31.etx */
  105. #define gestaltCPUClockSpeed 'pclk'    /* gestalt-selectors-31.etx */
  106.  
  107. char *IdentifyOwner(void)
  108. {
  109.     static char string[64];
  110.     unsigned char **owner;
  111.     
  112.     string[0]=0;
  113.     owner=GetString(-16096);    // Get owner's name from System file
  114.     if(owner!=NULL && *owner[0]>0){
  115.         memcpy(string,*owner,(*owner)[0]+1);
  116.         p2cstr((unsigned char *)string);
  117.     }
  118.     return string;
  119. }
  120.  
  121. char *IdentifyProcessor(void)
  122. {
  123.     char *processorName;
  124.     long sysArchitecture=gestalt68k,processor=1;                /* default */
  125.     int error;
  126.  
  127.     error=Gestalt(gestaltSysArchitecture,&sysArchitecture);
  128.     switch(sysArchitecture){
  129.         case gestalt68k:
  130.             error=Gestalt(gestaltProcessorType,&processor);
  131.             switch(processor){
  132.                 case gestalt68000: processorName="68000";break;
  133.                 case gestalt68010: processorName="68010";break;
  134.                 case gestalt68020: processorName="68020";break;
  135.                 case gestalt68030: processorName="68030";break;
  136.                 case gestalt68040: processorName="68040";break;
  137.                 default: processorName="unknown 68K processor";break;
  138.             }
  139.             break;
  140.         case gestaltPowerPC:
  141.             error=Gestalt(gestaltNativeCPUtype,&processor);
  142.             switch(processor){
  143.                 case gestaltCPU601: processorName="ppc601";break;
  144.                 case gestaltCPU603: processorName="ppc603";break;
  145.                  case 0x106:         processorName="ppc603e";break;/* PowerBook 5300 */
  146.                 case gestaltCPU604: processorName="ppc604";break;
  147.                 default: processorName="unknown PowerPC processor";break;
  148.             }
  149.             break;
  150.         default:
  151.             processorName="unknown processor";
  152.             break;
  153.     }
  154.     return processorName;
  155. }
  156.  
  157. char fpuName[][32]={
  158.     "no floating point unit","68881","68882","built-in floating point"
  159.     ,"unknown floating point unit","Software FPU"
  160. };
  161.  
  162. char *IdentifyFpu(void)
  163. {
  164.     long fpu,value;
  165.     int fpus=sizeof(fpuName)/sizeof(fpuName[0]);
  166.     static char fpuString[32];
  167.  
  168.     Gestalt(gestaltFPUType,&fpu);
  169.     if(fpu<0 || fpu>=fpus)fpu=fpus-2;
  170.     if(fpu==1 && Gestalt('FPUE',&value)==0)fpu=fpus-1;// Software FPU by John Neil & Assoc.
  171.     if(fpu>0)sprintf(fpuString,", %s",fpuName[fpu]);
  172.     else fpuString[0]=0;
  173.     return fpuString;
  174. }
  175.  
  176. char *IdentifyVM(void)
  177. {
  178.     // Based on gestalt-selectors-29.etx, available from Info-Mac.
  179.     Boolean vm;            // VM is on, possibly due to RAM Doubler
  180.     Boolean ramDoubler;    // RAM Doubler is on.
  181.     long value;
  182.     int error;
  183.     char *s="";
  184.     
  185.     error=Gestalt(gestaltVMAttr,&value);
  186.     vm=!error && value&(1L<<gestaltVMPresent);
  187.     error=Gestalt('vmem',&value);
  188.     ramDoubler=!error && value=='RaM2';
  189.     if(vm){
  190.         if(!ramDoubler)s="Using Virtual Memory. ";
  191.         else s="Using RAM Doubler. ";
  192.     }
  193.     return s;
  194. }
  195.  
  196. #if MATLAB && THINK_C // Save space. See 2/19/97 comment above.
  197.  
  198. char *IdentifyModel(void)
  199. {
  200.     int error;
  201.     long machine=0;
  202.     static char string[64];
  203.  
  204.     /* Before System 7.5 the MacOS supplied the model name. Now it merely supplies a
  205.         generic name, like "Power Macintosh". */
  206.     error=Gestalt(gestaltMachineType,&machine);
  207.     if(!error){
  208.         GetIndString((unsigned char *)string,kMachineNameStrID,machine);
  209.         p2cstr((unsigned char *)string);
  210.     }
  211.     return string;
  212. }
  213.  
  214. #else // See 2/19/97 comment above.
  215.  
  216. // System 7.5 took a step backwards and lacks
  217. // specific names for many machines, so I used Rene Ros's Gestalt Selectors List
  218. // to list all currently available Macs.
  219. char machineName[][36]={
  220.     "Unknown Mac"
  221.     ,"Mac 128K"
  222.     ,"Mac XL"
  223.     ,"Mac 512KE"
  224.     ,"Mac Plus"
  225.     ,"Mac SE"
  226.     ,"Mac II"
  227.     ,"Mac IIx"
  228.     ,"Mac IIcx"
  229.     ,"Mac SE-30"
  230.     ,"Mac Portable"
  231.     ,"Mac IIci"
  232.     ,"Unknown Mac"    /* 12 */
  233.     ,"Mac IIfx"
  234.     ,"Unknown Mac"
  235.     ,"Unknown Mac"
  236.     ,"Unknown Mac"
  237.     ,"Mac Classic","Mac IIsi","Mac LC","Mac Quadra 900","PowerBook 170"
  238.     ,"Mac Quadra 700","Mac Classic II","PowerBook 100","PowerBook 140","Quadra 950"
  239.     ,"Mac LC III"
  240.     ,"Unknown Mac"
  241.     ,"Mac PowerBook 210"
  242.     ,"Mac Centris 650"
  243.     ,"Unknown Mac"
  244.     ,"Mac PowerBook 230"
  245.     ,"Mac PowerBook 180"
  246.     ,"Mac PowerBook 160"
  247.     ,"Mac Quadra 800"    /* 35 */
  248.     ,"Mac Quadra 650"
  249.     ,"Mac LC II"
  250.     ,"Mac PowerBook Duo 250"
  251.     ,"PowerMac 9150"
  252.     ,"PowerMac 8100/110"    /* 40 */
  253.     ,"PowerMac 5200"    /* 41 */
  254.     ,"Unknown Mac"
  255.     ,"Unknown Mac"
  256.     ,"Mac IIvi"
  257.     ,"Mac Performa 600"
  258.     ,"Unknown Mac"
  259.     ,"PowerMac 7100/80"    /* 47 */
  260.     ,"Mac IIvx"
  261.     ,"Mac Color Classic"
  262.     ,"Mac PowerBook 165c"
  263.     ,"Unknown Mac"
  264.     ,"Mac Centris 610"
  265.     ,"Mac Quadra 610"
  266.     ,"Mac PowerBook 145,145b"
  267.     ,"PowerMac 8100/100"    /* 55 */
  268.     ,"Mac LC 520"
  269.     ,"Unknown Mac"
  270.     ,"Unknown Mac"
  271.     ,"Unknown Mac"
  272.     ,"Mac Centris 660AV"
  273.     ,"Unknown Mac"
  274.     ,"Mac Performa 46x"
  275.     ,"Unknown Mac"
  276.     ,"Unknown Mac"
  277.     ,"PowerMac 8100/80"    /* 65 */
  278.     ,"Unknown Mac"
  279.     ,"PowerMac 9500"    /* 67 */
  280.     ,"PowerMac 7500,7600"    /* 68 */
  281.     ,"PowerMac 8500"    /* 69 */
  282.     ,"Unknown Mac"
  283.     ,"Mac PowerBook 180c"
  284.     ,"Mac PowerBook 500,520,520c,540,540c" /* 72 */
  285.     ,"Unknown Mac"
  286.     ,"Unknown Mac"
  287.     ,"PowerMac 6100/60"    /* 75 */
  288.     ,"Unknown Mac"
  289.     ,"Mac PowerBook Duo 270c"
  290.     ,"Mac Quadra 840AV"
  291.     ,"Unknown Mac"
  292.     ,"Mac LC/Performa 550"
  293.     ,"Unknown Mac"
  294.     ,"Unknown Mac"
  295.     ,"Unknown Mac"
  296.     ,"Mac PowerBook 165"
  297.     ,"Unknown Mac"
  298.     ,"Unknown Mac"
  299.     ,"Unknown Mac"
  300.     ,"Mac TV"
  301.     ,"Mac LC/Performa 475"
  302.     ,"Unknown Mac"
  303.     ,"Unknown Mac"
  304.     ,"Mac LC 575"
  305.     ,"Unknown Mac"
  306.     ,"Mac Quadra 605"
  307.     ,"Unknown Mac"
  308.     ,"Unknown Mac"
  309.     ,"Unknown Mac"
  310.     ,"Mac LC/Quadra 630"
  311.     ,"Unknown Mac"
  312.     ,"PowerMac 6100/66"    /* 100 */
  313.     ,"PowerMac 6100"    /* 80 MHz, discovered by clock chippers */
  314.     ,"Mac PowerBook Duo 280"
  315.     ,"Mac PowerBook Duo 280c"
  316.     ,"PowerMac LC/Performa 475"
  317.     ,"PowerMac LC/Performa 575"
  318.     ,"PowerMac LC/Quadra 630"
  319.     ,"Unknown Mac"
  320.     ,"PowerMac 7200"    /* 108, also PowerMac 8200/100 */
  321.     ,"Unknown Mac"
  322.     ,"Unknown Mac"
  323.     ,"Unknown Mac"
  324.     ,"PowerMac 7100/66"    /* 112 */
  325.     ,"PowerMac 7100"    /* 80 MHz, discovered by clock chippers */
  326.     ,"Unknown Mac"
  327.     ,"Mac PowerBook 150"
  328.     ,"PowerMac Quadra700"
  329.     ,"PowerMac Quadra900"
  330.     ,"PowerMac Quadra950"
  331.     ,"PowerMac Centris610"
  332.     ,"PowerMac Centris650"
  333.     ,"PowerMac Quadra610"
  334.     ,"PowerMac Quadra650"
  335.     ,"PowerMac Quadra800"
  336.     ,"PowerBook 2300c"    /* 124 */
  337.     ,"Unknown Mac"
  338.     ,"Unknown Mac"
  339.     ,"Unknown Mac"
  340.     ,"PowerBook 5300"
  341. };
  342.  
  343. char *IdentifyCompiler(void)
  344. {
  345.     static char string[200];
  346.     char *compiler,*longs,*floating,version[4],*universal;
  347.     double v=0;
  348.     Boolean fractionalVersion=0;
  349.     
  350.     string[0]=0;
  351.     compiler="";
  352.     #if THINK_C && !SYMANTEC_C
  353.         compiler="Symantec THINK C";
  354.         if(THINK_C==1)v=4;
  355.         else v=THINK_C;
  356.     #endif
  357.     #if THINK_CPLUS || SYMANTEC_C
  358.         #if __cplusplus || THINK_CPLUS
  359.             compiler="Symantec C++";
  360.         #else
  361.             compiler="Symantec C";
  362.         #endif
  363.         #if THINK_CPLUS
  364.             v=THINK_CPLUS;
  365.         #else
  366.             fractionalVersion=1;
  367.             v=SYMANTEC_C/0x100 + 0.1*(SYMANTEC_C/0x10%0x10) + 0.01*(SYMANTEC_C%0x10);
  368.         #endif
  369.     #endif
  370.     #if applec
  371.         compiler="MPW C";
  372.     #endif
  373.     #if __MWERKS__
  374.         compiler="Metrowerks CodeWarrior C";
  375.         #if __MWERKS__>1
  376.             fractionalVersion=1;
  377. // The Inside CodeWarrior 10 book, p. CL-196, says this should work.
  378.             v=__MWERKS__/0x100 + 0.1*(__MWERKS__/0x10%0x10) + 0.01*(__MWERKS__%0x10);
  379. // But in CW10 that returns v==16.00, whereas I get 1.6 from a Finder Get Info on 
  380. // the C/C++ compiler plug in. So I divide by 10.
  381.             v=v/10.;
  382.         #else
  383.             #if defined(__MC68K__)||defined(__POWERPC__)||defined(__INTEL__)
  384.                 v=6;
  385.             #else
  386.                 if(!iscntrl(0))v=4;    // bug in version 4.5 and earlier
  387.                 else v=5;
  388.             #endif
  389.         #endif
  390.     #endif
  391.     if(v>0){
  392.         if(fractionalVersion)sprintf(version,"%.2f ",v);
  393.         else sprintf(version,"%.0f ",v);
  394.     }else sprintf(version,"");
  395.     if(GENERATING68020)longs="68020";
  396.     else{
  397.         #if GENERATINGPOWERPC
  398.             longs="PowerPC";
  399.         #else
  400.             longs="68000";
  401.         #endif
  402.     }
  403.     if(GENERATING68881)floating=" and 68881";
  404.     else floating="";
  405.     universal="";
  406.     if(sizeof(double)==12){
  407.         #if THINK_C
  408.             #if !__option(native_fp)
  409.                 universal="\"universal\"-format ";
  410.             #endif
  411.         #endif
  412.     }
  413.     sprintf(string,"Compiled by %s %sfor %s%s, %ldB int and %s%ldB double."
  414.         ,compiler,version,longs,floating,sizeof(int),universal,sizeof(double));
  415.     return string;
  416. }
  417.  
  418. char *IdentifyModel(void)
  419. {
  420.     int error;
  421.     long machine=0,value;
  422.     int machines=sizeof(machineName)/sizeof(machineName[0]);
  423.     static char string[64];
  424.     char cpuName[32]="";
  425.     long cpuHz=0,busHz=0;
  426.     Boolean hasL2Cache,powerMgrExists;
  427.     
  428.     #if 0
  429.         /* Before System 7.5 the MacOS supplied the model name. Now it merely supplies a
  430.             generic name, like "Power Macintosh". */
  431.         error=Gestalt(gestaltMachineType,&machine);
  432.         if(!error){
  433.             GetIndString((unsigned char *)string,kMachineNameStrID,machine);
  434.             p2cstr((unsigned char *)string);
  435.             if(strlen(string)==0){
  436.                 if(machine<0 || machine>=machines)machine=0;
  437.                 sprintf(string,"%s",machineName[machine]);
  438.             }
  439.         }
  440.     #endif
  441.     /* The model names in the machineName[] table include clock speed, where appropriate,
  442.     for the pre-PCI Macs, e.g. 6100/60, but omit clock speed for the PCI Macs, since 
  443.     PCI Macs must run System 7.5.2 or better, which include gestaltCPUClockSpeed, whereas
  444.     pre-PCI Macs may be running 7.5.1 which did not include gestaltCPUClockSpeed. 
  445.     If the actual clock speed is available we always use it, overwriting the nominal speed if
  446.     necessary. */
  447.     error=Gestalt(gestaltMachineType,&machine);
  448.     strcpy(string,machineName[machine]);
  449.     GetCPUProperties(cpuName,&cpuHz,&hasL2Cache);    // useful only on PCI Macs
  450.     error=Gestalt(gestaltBusClockSpeed,&busHz);        // requires System 7.5.2 or better
  451.     error=Gestalt(gestaltCPUClockSpeed,&cpuHz);        // requires System 7.5.2 or better
  452.     if(cpuHz==0){
  453.         Gestalt(gestaltPowerMgrAttr,&value);        // Only on powerbooks I think.
  454.         powerMgrExists=value&(1L<<gestaltPMgrExists);
  455.         if(powerMgrExists)cpuHz=1000000*GetCPUSpeed();
  456.     }
  457.     if(cpuHz>0){
  458.         int i=strlen(string);
  459.         // remove the nominal speed, if present, before appending the actual speed
  460.         if(i>4 && string[i-4]=='/' && isdigit(string[i-3]) && isdigit(string[i-2]) && isdigit(string[i-1]))
  461.             string[i-4]=0;
  462.         if(i>3 && string[i-3]=='/' && isdigit(string[i-2]) && isdigit(string[i-1]))
  463.             string[i-3]=0;
  464.         sprintf(string,"%s/%ld",string,cpuHz/1000000);
  465.     }
  466.     return string;
  467. }
  468.  
  469. char *IdentifyVideo(GDHandle device)
  470. // E.g. "PowerBook 170 \"Macintosh D Built-In Video\" (.Display_Video_Apple_TIM)"
  471. {
  472.     static char string[256];
  473.     long quickDraw;
  474.     char *slotName;
  475.  
  476.     string[0]=0;
  477.     Gestalt(gestaltQuickdrawVersion,&quickDraw);
  478.     if(quickDraw<gestalt8BitQD){
  479.         sprintf(string,"%s ",IdentifyModel());
  480.         sprintf(string,"%s\"%s\"",string,"1-bit QuickDraw");
  481.     }else{
  482.         slotName=GetDeviceSlotName(device);
  483.         if(strlen(slotName)==0 || strcmp(slotName,"0")==0)sprintf(string,"%s ",IdentifyModel());
  484.         sprintf(string,"%s\"%s\"",string,GDCardName(device));
  485.         if(GDVersion(device)==0)sprintf(string,"%s (%s)",string,GDNameStr(device));
  486.         else sprintf(string,"%s (%s version %d)"
  487.             ,string,GDNameStr(device),(int)GDVersion(device));
  488.         if(strlen(slotName)>0 && strcmp(slotName,"0")!=0)sprintf(string,"%s slot %s",string,slotName);
  489.     }
  490.     return string;
  491. }
  492.  
  493. char *IdentifyApplication(void)    // Returns name of application.
  494. {
  495.     static char string[32];
  496.  
  497.     memcpy(string,LMGetCurApName(),32);
  498.     p2cstr((unsigned char *)string);
  499.     return string;
  500. }
  501.  
  502. char *IdentifyMachineAndType(void);
  503.  
  504. char *IdentifyMachineAndType(void)
  505. {
  506.     int error;
  507.     long machine=0;
  508.     char *s;
  509.  
  510.     s=IdentifyMachine();
  511.     error=Gestalt(gestaltMachineType,&machine);
  512.     sprintf(s,"%s GestaltMachineType %ld.",s,machine);
  513.     return s;
  514. }
  515.  
  516. char *IdentifyMachine(void)
  517. {
  518.     int error;
  519.     long processor=-1,system,value;
  520.     static char string[256];
  521.     Boolean cacheData=1,cacheInstructions=1;
  522.     long romSize,romVersion,qD;
  523.     char *owner;
  524.     char cpuName[32]="";
  525.     long cpuHz=0,busHz=0;
  526.     Boolean hasL2Cache;
  527.     char *cache;
  528.     
  529.     GetCPUProperties(cpuName,&cpuHz,&hasL2Cache);    /* works only on PCI Macs */
  530.     error=Gestalt(gestaltBusClockSpeed,&busHz);        /* works only on PCI Macs */
  531.     error=Gestalt(gestaltCPUClockSpeed,&cpuHz);        /* works only on PCI Macs */
  532.     string[0]=0;
  533.     error=Gestalt(gestaltSystemVersion,&system);
  534.     if(error)return string;                        /* Gestalt not available */
  535.     owner=IdentifyOwner();
  536.     if(strlen(owner)>0)sprintf(string,"%s's ",owner);
  537.     sprintf(string,"%s%s",string,IdentifyModel());
  538.     if(strlen(cpuName)>0){
  539.         if(hasL2Cache)cache=", L2 cache";
  540.         else cache="";
  541.     }else cache="";
  542.     sprintf(string,"%s, %s%s%s, System %lx.%lx"
  543.         ,string,IdentifyProcessor(),cache,IdentifyFpu(),system/0x100,system%0x100/0x10);
  544.     system%=0x10;
  545.     if(system)sprintf(string,"%s.%lx",string,system);
  546.     sprintf(string,"%s.",string);
  547.     if(0){    // The rest is boring, so I've disabled it.
  548.         Gestalt(gestaltROMSize,&romSize);
  549.         Gestalt(gestaltROMVersion,&romVersion);
  550.         sprintf(string,"%s, %ldK ROM version %ld+%ld*256."
  551.             ,string,romSize/1024,romVersion%256,romVersion/256);
  552.         value=0;
  553.         Gestalt(gestaltAddressingModeAttr,&value);
  554.         {
  555.             if(value&1L<<gestalt32BitAddressing)sprintf(string,"%s 32-bit addressing.",string);
  556.             else sprintf(string,"%s 24-bit addressing.",string);
  557.         }
  558.         Gestalt(gestaltQuickdrawVersion,&qD);
  559.         switch(qD/0x100){
  560.             case 0:
  561.                 sprintf(string,"%s 1-bit QuickDraw.",string);
  562.                 break;
  563.             case 1:
  564.                 sprintf(string,"%s 8-bit QuickDraw.",string);
  565.                 break;
  566.             case 2:
  567.                 sprintf(string,"%s 32-bit QuickDraw 1.%02lx.",string,qD%0x100);
  568.                 break;
  569.             default:
  570.                 sprintf(string,"%s QuickDraw 0x%lx.",string,qD);
  571.                 break;
  572.         }
  573.     }
  574.     return string;
  575. }
  576.  
  577. char *IdentifyGreenwichMeanTime(void)
  578. {
  579.     MachineLocation location;
  580.     long t;
  581.     double hours;
  582.     static char s[64];
  583.  
  584.     ReadLocation(&location);
  585.     if(location.latitude!=0 || location.longitude!=0){
  586.         #if UNIVERSAL_HEADERS>1
  587.             t=location.u.gmtDelta & 0x00FFFFFF;
  588.         #else
  589.             t=location.gmtFlags.gmtDelta & 0x00FFFFFF;
  590.         #endif
  591.         if(t & 0x800000)t|=0xFF000000;
  592.         hours=fabs(t/3600.0);
  593.         if(hours==floor(hours))sprintf(s,"%.0f",hours);
  594.         else sprintf(s,"%.1f",hours);
  595.         if(t<0)sprintf(s,"%s hours west of Greenwich mean time.",s);
  596.         else sprintf(s,"%s hours east of Greenwich mean time.",s);
  597.     }else s[0]=0;
  598.     return s;
  599. }
  600.  
  601. #endif    // !(MATLAB && THINK_C)
  602.  
  603. /************************************************************************/
  604.  
  605. /*
  606. Using Apple's NameRegistry
  607.  
  608. void GetVideoProperties(GDHandle device,char *slotName,char *cardName,char *cardModel);
  609. void GetCPUProperties(char *cpuName,long *cpuHz,Boolean *hasL2Cache);
  610.  
  611. Two routines that use the new Name Registry (available only on PCI PowerMacs) to
  612. determine the cpu clock rate, presence of L2 cache, and the name of the PCI video
  613. card. The routines return zeroes if the Name Registry is not available (i.e. on
  614. non-PCI Macs), or if compiled as 68k code.
  615.  
  616. WARNING: to effectively use Apple's NameRegistry in your project you MUST have Apple's
  617. NameRegistryLib, which contains the glue code to access the MacOS. NameRegistryLib 
  618. is in the VideoToolbox Libs folder; add it to your project and use the pop-up 
  619. menu to select "import 'weak'".) As of 1/96, Apple has
  620. distributed NameRegistry.h and NameRegistryLib only as part of the Apple
  621. Developer Mailing and the SDK Subscription (either costs $250/year from APDA). These 
  622. two files are not included with Metrowerks CodeWarrior 8. You don't need
  623. NameRegistry.h, because Identify.c includes the needed definitions, but you do need
  624. NameRegistryLib, which is in the VideoToolbox Libs folder. Alternatively,
  625. you may set the flag NO_NAME_REGISTRY_LIB to true, which will disable the rest of 
  626. this file, but allows you to link and run your programs.
  627.  
  628. Once compiled and linked with the NameRegistryLib glue, this code will run on any
  629. PCI PowerMac. A temporary #if section takes care of the missing header file, so
  630. you'll be able to compile, but I don't think you'll be able to link this unless
  631. you have NameRegistryLib. I confess to being somewhat unsure on the last point
  632. since there are suggestions in the original source files that NameRegistryLib
  633. could be installed in the System:Extensions folder of the target machine instead
  634. of being linked into the application itself. That is apparently what the call
  635. below to Code Fragment Manager is for. However, I don't really understand this
  636. arcane stuff (i.e. "weak linking"), and it didn't seem worth learning for the
  637. routines in this file. Metrowerks has a "weak-linking" option, but limited
  638. experimentation suggests that you have to have the library in order to weak-link
  639. to it, which is no help at all for someone who doesn't have the library.
  640.  
  641. HISTORY:
  642. 10/13/95 dgp wrote GetVideoProperties() and GetCPUProperties(), based on general
  643.         advice from Apple (below) and 
  644.         the PCISlotsUtils.cp source file for Apple's "PCI Slot Peek" demo,
  645.         in the PCI developer's kit included on the September '95 Developer's CD. 
  646.  
  647. Hi Denis
  648.  
  649. Thank you for your link (ID# 151426) concerning how to detect a L2 cache and
  650. get the processor speed.
  651.  
  652. Let's look at the cache first. Before the introduction of the PCI Power
  653. Macintosh computers there was no API to detect the presents of this cache. On
  654. a PCI Macintosh there is the Name Registry. This registry contains this
  655. information in the form of a property. The property name is "name" and if
  656. there is a L2 cache the property value is "l2-cache". Look at the Developer CD
  657. for Sept 95. In the What's New folder there is the PCI DDK. There is a
  658. program called Display Name Registry that will show what I have just explained.
  659. Of course it must run on a PCI machine. There is also a document called
  660. "Designing PCI Cards&Drivers...." that shows examples of using the Name
  661. Registry to search for system resources.
  662.  
  663. Now the CPU speed. Like the last case, before PCI Macs there was no direct
  664. call that could be made to determine CPU speed. There are Gestalt calls for
  665. CPU type if that's any help. However, there are CPU accelerator cards so that
  666. would present a problem. The two calls you mentioned (GetCPUSPeed &
  667. MaximumProcessSpeed) are both for portable Macs that use the Power Manager.
  668. The traps for these calls are not implemented on other Macs. At least not the
  669. 9500 that I tried. However, PCI Macs and the Name Registry contain this
  670. information also. Again go to Display Name Registry and look at the
  671. Devices:device-tree;PowerPC,604 property. Expand it and there is an additional
  672. sub property called "clock-frequency". My 9500 show 132000000.
  673.  
  674. So you have what you want but starting with PCI Macs.
  675.  
  676. Regards
  677.  
  678. Wayne Flansburg
  679. Developer Technical Support
  680. Apple Computer
  681. 12 October 1995
  682. */
  683.  
  684. #ifndef __CODEFRAGMENTS__
  685.     #include <CodeFragments.h>
  686. #endif
  687. // The version macro UNIVERSAL_INTERFACES_VERSION is defined in Apple's ConditionalMacros.h,
  688. // but only since version 2.1 (which was distributed with CodeWarrior 8).
  689. #if UNIVERSAL_INTERFACES_VERSION>=0x0212
  690.     #ifndef __NAMEREGISTRY__
  691.         #include <NameRegistry.h>
  692.     #endif
  693. #else
  694.     #if !defined(NO_NAME_REGISTRY_LIB) && !defined(__NAMEREGISTRY__)
  695.         // As of 10/13/95, Apple has distributed NameRegistry.h and NameRegistryLib only to 
  696.         // Apple Developers. Neither is included with Metrowerks CodeWarrior 7.
  697.         // The following definitions and prototypes, copied from NameRegistry.h, are just 
  698.         // enough to allow compilation of this file without the header file. However, 
  699.         // you'll still need NameRegistryLib in order to link. 
  700.         // NameRegistryLib is in Metrowerks CodeWarrior's 
  701.         // "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS PPC:" folder.
  702.         typedef UInt32 RegIterationOp;
  703.         typedef RegIterationOp RegEntryIterationOp;
  704.         struct RegEntryIter {
  705.             void *opaque;
  706.         };
  707.         typedef struct RegEntryIter *RegEntryIterPtr;
  708.         typedef struct RegEntryIter RegEntryIter;
  709.         struct RegEntryID {
  710.             UInt8 opaque[16];
  711.         };
  712.         typedef struct RegEntryID RegEntryID, *RegEntryIDPtr;
  713.         typedef char RegCStrPathName;
  714.         typedef UInt32 RegPathNameSize;
  715.         enum {
  716.             kRegMaximumPropertyNameLength = 31,                            /* Max length of Property Name */
  717.             kRegPropertyNameTerminator    = 0x00,                            /* '\0' */
  718.             kRegIterContinue = 0x1UL
  719.         };
  720.         typedef char RegPropertyName, *RegPropertyNamePtr, RegPropertyNameBuf[kRegMaximumPropertyNameLength + 1];
  721.         typedef UInt32 RegPropertyValueSize;
  722.         extern OSStatus RegistryEntryIterateCreate(RegEntryIter *cookie);
  723.         extern OSStatus RegistryEntryIterateDispose(RegEntryIter *cookie);
  724.         extern OSStatus RegistryEntryIterate(RegEntryIter *cookie, RegEntryIterationOp relationship, RegEntryID *foundEntry, Boolean *done);
  725.         extern OSStatus RegistryEntryToPathSize(const RegEntryID *entryID, RegPathNameSize *pathSize);
  726.         extern OSStatus RegistryCStrEntryToPath(const RegEntryID *entryID, RegCStrPathName *pathName, RegPathNameSize pathSize);
  727.         extern OSStatus RegistryPropertyGetSize(const RegEntryID *entryID, const RegPropertyName *propertyName, RegPropertyValueSize *propertySize);
  728.         extern OSStatus RegistryPropertyGet(const RegEntryID *entryID, const RegPropertyName *propertyName, void *propertyValue, RegPropertyValueSize *propertySize);
  729.         extern OSStatus RegistryEntryIDDispose(RegEntryID *id);
  730.     #endif
  731. #endif
  732. #include <stdio.h>
  733. #include <string.h>
  734. /*
  735.     RegPropertyModifiers propertyModifiers;
  736.     if(0 && !error){
  737.         error=RegistryPropertyGetMod(&entry,foundProperty,&propertyModifiers);
  738.     }
  739. */
  740.  
  741. void GetVideoProperties(GDHandle device,char *slotName,char *cardName,char *cardModel);
  742. void GetCPUProperties(char *cpuName,long *cpuHz,Boolean *hasL2Cache);
  743.  
  744. void GetVideoProperties(GDHandle device,char *slotName,char *cardName,char *cardModel)
  745. {
  746. #if NO_NAME_REGISTRY_LIB || !GENERATINGPOWERPC
  747.     device;
  748.     slotName[0]=0;
  749.     cardName[0]=0;
  750.     cardModel[0]=0;
  751.     return;
  752. #else
  753.     /*
  754.     Assume we're running native on ppc.
  755.     If this were compiled as 68k code, the calls to the NameRegistryLib, which is PPC code, 
  756.     would require intervention by the Mixed Mode Manager,
  757.     and I decided not to bother with that complication, since there seems little point in
  758.     compiling programs as 68k code to run on a PowerPC. TimeVideo is distributed as a fat 
  759.     binary, so it always runs native.
  760.     */
  761.     OSStatus error;
  762.     RegEntryIter cookie;
  763.     Boolean done;
  764.     RegEntryIterationOp    op;
  765.     RegEntryID entry;
  766.     RegCStrPathName *pathName;
  767.     RegPathNameSize pathNameSize;
  768.     RegPropertyNameBuf foundProperty;
  769.     RegPropertyValueSize propertySize;
  770.     long templong;
  771.     short driverRef;
  772.     
  773.     slotName[0]=0;
  774.     cardName[0]=0;
  775.     cardModel[0]=0;
  776.     if(device==NULL)return;
  777.     {
  778.         /*
  779.         To determine whether you're running on a PCI Mac, you must first check if the
  780.         NameRegistry exists. There is a Gestalt Manager selector for
  781.         this, 'nreg'. If it exists, the value returned will be the version number
  782.         (number 1 for now) of the Name Registry. Otherwise, you should get a
  783.         gestaltUndefSelectorErr. If the Name Registry does not exist then you should
  784.         assume that it is not a PCI based machine; it may have NuBus or no bus at all.
  785.         */
  786.         error=Gestalt(gestaltNameRegistryVersion,&templong);
  787.         if(error)return;    // No PCI slots
  788.         /*
  789.         *** I didn't add this yet --- dgp ***
  790.         You can use the Name Registry to determine if a PCI bus exists. To do this you
  791.         should use RegistryEntrySearch to locate an entry/node having a known
  792.         property/value, propertyName = "devic-type", and propertyValue = "pci"  If an
  793.         entry is found that has that known property/value (noErr and done = "False"),
  794.         there is a PCI bus.
  795.         Wayne Flansburg
  796.         DTS
  797.         Apple Computer
  798.         1/26/96
  799.         */
  800.     }
  801.     {
  802.         // If NameRegistryLib is weak-linked, it may be missing at runtime, so we
  803.         // check for the library, to prevent a crash if we try to access the library's exports.
  804.         CFragConnectionID connID;
  805.         Ptr mainAddr;
  806.         Str255 errName;
  807.         
  808.         error=Gestalt(gestaltCFMAttr,&templong);    // Code Fragment Manager?
  809.         if(!error)error=GetSharedLibrary((ConstStr63Param)"\pNameRegistryLib"
  810.             ,kAnyCFragArch,kFindCFrag,&connID,&mainAddr,errName);
  811.         if(error)return;    // No NameRegistryLib
  812.     }
  813.     op=kRegIterContinue;
  814.     error=RegistryEntryIterateCreate(&cookie);
  815.     if(!error){
  816.         done=FALSE;
  817.         while (!error && !done){
  818.             error=RegistryEntryIterate(&cookie,op,&entry,&done);
  819.             if(!error && !done){
  820.                 pathName=NULL;
  821.                 error=RegistryEntryToPathSize(&entry,&pathNameSize);
  822.                 if(!error){
  823.                     pathName=(RegCStrPathName *) NewPtr(pathNameSize);
  824.                     if(pathName==NULL)error=MemError();
  825.                 }
  826.                 if(!error){
  827.                     error=RegistryCStrEntryToPath(&entry,pathName,pathNameSize);
  828.                     //printf("%s\n",pathName);    // debugging
  829.                 }
  830.                 if(!error){
  831.                     // Found a video device
  832.                     strcpy(foundProperty,"driver-ref");
  833.                     propertySize=0;
  834.                     error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  835.                     if(!error){
  836.                         assert(propertySize==sizeof(driverRef));
  837.                         error=RegistryPropertyGet(&entry,foundProperty,&driverRef,&propertySize);
  838.                         if(!error && driverRef==(*device)->gdRefNum){
  839.                             done=TRUE; // we found the correct driver
  840.                             strcpy(foundProperty,"name");
  841.                             propertySize=0;
  842.                             error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  843.                             if(!error)error=RegistryPropertyGet(&entry,foundProperty,cardName,&propertySize);
  844.                             strcpy(foundProperty,"model");
  845.                             propertySize=0;
  846.                             error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  847.                             if(!error)error=RegistryPropertyGet(&entry,foundProperty,cardModel,&propertySize);
  848.                             propertySize=0;
  849.                             strcpy(foundProperty,"AAPL,slot-name");
  850.                             error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  851.                             if(!error)error=RegistryPropertyGet(&entry,foundProperty,slotName,&propertySize);
  852.                             // PCI slot names on Power Macintosh currently are of form : A1,B1,C1,D2,E2,F2
  853.                         }
  854.                     }else error=noErr;    // there is a card but NO display attached (no open driver)
  855.                 }
  856.                 if(pathName != NULL)DisposePtr((Ptr) pathName);
  857.                 RegistryEntryIDDispose(&entry);
  858.             }
  859.         }
  860.         RegistryEntryIterateDispose(&cookie);
  861.     }
  862.     return;
  863. #endif
  864. }    /* GetVideoProperties */
  865.  
  866. void GetCPUProperties(char *cpuName,long *cpuHz,Boolean *hasL2Cache)
  867. {
  868. #if NO_NAME_REGISTRY_LIB || !GENERATINGPOWERPC
  869.     cpuName[0]=0;
  870.     *cpuHz=0;
  871.     *hasL2Cache=0;
  872.     return;
  873. #else
  874.     /*
  875.     Assume we're running native on ppc.
  876.     If this were compiled as 68k code, the calls to the NameRegistryLib, which is PPC code, 
  877.     would require intervention by the Mixed Mode Manager,
  878.     and I decided not to bother with that complication, since there seems little point in
  879.     compiling programs as 68k code to run on a PowerPC. TimeVideo is distributed as a fat 
  880.     binary, so it always runs native.
  881.     */
  882.     OSStatus error;
  883.     RegEntryIter cookie;
  884.     Boolean done;
  885.     RegEntryIterationOp    op;
  886.     RegEntryID entry;
  887.     RegCStrPathName *pathName;
  888.     RegPathNameSize pathNameSize;
  889.     RegPropertyNameBuf foundProperty;
  890.     RegPropertyValueSize propertySize;
  891.     long templong;
  892.     char *propertyValue[256];
  893.     
  894.     cpuName[0]=0;
  895.     *cpuHz=0;
  896.     *hasL2Cache=0;
  897.     {
  898.         // If the NameRegistryLib is weak-linked, and it is missing, we need to
  899.         // check for the library, to prevent a crash if we try to access the library's exports;
  900.         // currently the Finder reports if the library is missing
  901.         CFragConnectionID        connID;
  902.         Ptr                        mainAddr;
  903.         Str255                    errName;
  904.         
  905.         error=Gestalt(gestaltCFMAttr,&templong);    // Code Fragment Manager?
  906.         if(!error)error=GetSharedLibrary((ConstStr63Param)"\pNameRegistryLib"
  907.             ,kAnyCFragArch,kFindCFrag,&connID,&mainAddr,errName);
  908.         if(error)return;    // No NameRegistryLib
  909.     }
  910.     error=Gestalt(gestaltNameRegistryVersion,&templong);
  911.     if(error)return;    // No PCI slots
  912.  
  913.     op=kRegIterContinue;
  914.     error=RegistryEntryIterateCreate(&cookie);
  915.     if(!error){
  916.         done=FALSE;
  917.         while (!error && !done){
  918.             error=RegistryEntryIterate(&cookie,op,&entry,&done);
  919.             if(!error && !done){
  920.                 pathName=NULL;
  921.                 error=RegistryEntryToPathSize(&entry,&pathNameSize);
  922.                 if(!error){
  923.                     pathName=(RegCStrPathName *) NewPtr(pathNameSize);
  924.                     if(pathName==NULL)error=MemError();
  925.                 }
  926.                 if(!error){
  927.                     error=RegistryCStrEntryToPath(&entry,pathName,pathNameSize);
  928.                     //printf("%s\n",pathName);    // debugging
  929.                 }
  930.                 if(!error){
  931.                     propertySize=0;
  932.                     strcpy(foundProperty,"device_type");
  933.                     error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  934.                     if(!error)assert(propertySize<=sizeof(propertyValue));
  935.                     if(!error){
  936.                         error=RegistryPropertyGet(&entry,foundProperty,propertyValue,&propertySize);
  937.                         // Is it what we want?
  938.                         if(!error && strcmp("cpu",(char *)propertyValue)!=0)error=-1; // no
  939.                     }
  940.                     if(!error){
  941.                         strcpy(foundProperty,"clock-frequency");
  942.                         error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  943.                     }
  944.                     if(!error)assert(propertySize==sizeof(*cpuHz));
  945.                     if(!error){
  946.                         error=RegistryPropertyGet(&entry,foundProperty,cpuHz,&propertySize);
  947.                     }
  948.                     if(!error){
  949.                         strcpy(foundProperty,"name");
  950.                         error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  951.                     }
  952.                     if(!error)assert(propertySize<256);
  953.                     if(!error){
  954.                         error=RegistryPropertyGet(&entry,foundProperty,cpuName,&propertySize);
  955.                     }
  956.                     if(!error){
  957.                         strcpy(foundProperty,"l2-cache");
  958.                         error=RegistryPropertyGetSize(&entry,foundProperty,&propertySize);
  959.                         if(!error)*hasL2Cache=1;
  960.                         else *hasL2Cache=0;
  961.                     }
  962.                     error=0;
  963.                 }
  964.                 if(pathName != NULL)DisposePtr((Ptr) pathName);
  965.                 RegistryEntryIDDispose(&entry);
  966.             }
  967.         }
  968.         RegistryEntryIterateDispose(&cookie);
  969.     }
  970.     return;
  971. #endif
  972. }    /* GetCPUProperties */
  973.